import * as redis from 'redis';
import { LogFactory, Logger } from './log';

export class Redis{
    log:Logger = LogFactory.inst().getLogger("Redis");
    rc:redis.RedisClient;

    constructor(host:string, port:number){
        let self = this;
        this.rc = redis.createClient(port, host, {
            retry_strategy: (options)=>{
                switch(options.error.code){
                    case 'ECONNREFUSED':
                        this.log.error("connect are refused");
                    break;
                }
                // reconnect after 
                this.log.info("try to connect, host:", host, "port:", port);
                return Math.max(options.attempt * 100, 3000);
            }
        })
        this.rc.on("ready", () => {
            this.log.info("open success, host:", host, "port:", port);
        });
        this.rc.on("error", (err) => {
            this.log.error("err:", err);
        });
    }

    async set(key:string,value:string):Promise<boolean>{
        return new Promise<boolean>((resolve, reject) => {
            this.rc.set(key,value,(err:Error|null, reply:"OK")=>{
                if (err){
                    this.log.error("set:", err);
                    reject(err);
                }else{
                    resolve(true);
                }
            });
        });
    }

    async setex(key: string, ex: number, value: string): Promise<boolean> {
        return new Promise<boolean>((resolve, reject) => {
            this.rc.setex(key, ex, value, (err: Error | null, reply: string) => {
                if (err){
                    this.log.error("setex:", err);
                    reject(err);
                }else{
                    resolve(true);
                }
            });
        });
    }

    async get(key:string):Promise<string|false>{
        return new Promise<string|false>((resolve, reject) => {
            this.rc.get(key,(err:Error|null, reply:string)=>{
                if (err){
                    this.log.error("get:", err);
                    reject(err);
                }else{
                    resolve(reply);
                }
            });
        });
    }

    async del(key:string):Promise<number|false>{
        return new Promise<number>((resolve, reject) => {
            this.rc.del(key,(err:Error|null, reply:number)=>{
                if (err){
                    this.log.error("del:", err);
                    reject(false);
                }else{
                    resolve(reply);
                }
            });
        });
    }

    async hmset(key: string, ...args: Array<string>): Promise<boolean> {
        return new Promise<boolean>((resolve, reject) => {
            this.rc.hmset(key, args, (err: Error | null, reply: String) => {
                if (err) {
                    this.log.error("hmset:", err);
                    reject(false);
                } else {
                    resolve(true);
                }
            });
        });
    }

    async hmget(key:string, ...args: Array<string>):Promise<Array<string|boolean>>{
        return new Promise<Array<string|boolean>>((resolve, reject) => {
            this.rc.hmget(key, args, (err: Error | null, reply: Array<string>) => {
                if (err){
                    this.log.error("hmget:", err);
                    reject(false);
                }else{
                    resolve(reply);
                }
            });
        });
    }

    async hdel(key: string, ...args: Array<string>): Promise<boolean> {
        return new Promise<boolean>((resolve, reject) => {
            this.rc.hdel(key, ...args, (err: Error | null, reply: number) => {
                if (err) {
                    this.log.error("hdel:", err);
                    reject(false);
                } else {
                    resolve(true);
                }
            });
        });
    }
}